package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmMaterialService;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsAutoScanService wmNewsAutoScanService;

    /**
     * 查询文章
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {

        //1.检查参数
        if (dto == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //分页参数检查
        dto.checkParam();
        //获取当前登录人的信息
        WmUser user = WmThreadLocalUtil.getUser();
        if (user == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        //2.分页条件查询
        IPage page = new Page(dto.getPage(), dto.getSize());
        LambdaQueryWrapper<WmNews> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //状态精确查询
        if (dto.getStatus() != null) {
            lambdaQueryWrapper.eq(WmNews::getStatus, dto.getStatus());
        }

        //频道精确查询
        if (dto.getChannelId() != null) {
            lambdaQueryWrapper.eq(WmNews::getChannelId, dto.getChannelId());
        }

        //时间范围查询
        if (dto.getBeginPubdate() != null && dto.getEndPubdate() != null) {
            lambdaQueryWrapper.between(WmNews::getPublishTime, dto.getBeginPubdate(), dto.getEndPubdate());
        }


        //关键字模糊查询
        if (StringUtils.isNotBlank(dto.getKeyword())) {
            lambdaQueryWrapper.like(WmNews::getTitle, dto.getKeyword());
        }

        //查询当前登录用户的文章
        lambdaQueryWrapper.eq(WmNews::getUserId, user.getId());

        //发布时间倒序查询
        lambdaQueryWrapper.orderByDesc(WmNews::getCreatedTime);

        page = page(page, lambdaQueryWrapper);

        //3.结果返回
        ResponseResult responseResult = new PageResponseResult(dto.getPage(), dto.getSize(), (int) page.getTotal());
        responseResult.setData(page.getRecords());

        return responseResult;
    }


    @Autowired
    private WmMaterialService wmMaterialService;

    /**
     * 存入文章或提交为草稿，修改文章或草稿，三合一
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult submitNews(WmNewsDto dto) {
        //1 参数判断判断content文章内容是否为空
        if (dto.getContent() == null) {
            //文章内容都没有，那么直接返回
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //type==-1，则把type赋值为null
        if(dto.getType()==-1){
            //要改type的值，不改数据库存不进去-1，因为是type类型是tinyint,一个长度
            dto.setType(null);
        }
        //1.1 新增或者修改文章
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(dto, wmNews);
        //封装dto中没有的数据
        wmNews.setUserId(WmThreadLocalUtil.getUser().getId());
        wmNews.setCreatedTime(new Date());
        //封面图片进行封装
        if (dto.getImages().size() > 0 && dto.getImages() != null) {
            String imagesStr = StringUtils.join(dto.getImages(), ',');
            wmNews.setImages(imagesStr);
        }
        insertOrUpdateNews(wmNews);

        //2.1 判断是否为草稿
        if (dto.getStatus() == 0) {
            //2.2 判断是否为草稿，如果是草稿，就只新增wm_news表，然后结束方法
            return ResponseResult.errorResult(AppHttpCodeEnum.CAO_GAO);
        }

        //TODO 如果不是草稿，那么新增和修改都会走下列的代码，是草稿就直接上面结束方法

        //2.3 不是草稿，新增中间表
        //2.3.1 要知道内容图片与文章的关系，抽取内容图片
        List<String> contentImagesList = extractImagesFromContent(dto);
        //3 文章内容图片与中间表
        insertContentImagesToWmNewsMaterial(wmNews, contentImagesList);
        //4 文章封面图片与中间表
        insertCoverImagesToWmNewsMaterial(wmNews, dto, contentImagesList);

        //异步调用自动审核业务
        try {
            wmNewsAutoScanService.autoScanWmNews(wmNews.getId());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return ResponseResult.errorResult(AppHttpCodeEnum.SUBMIT_ARTICLE_SUCCESS);

    }


    /**
     * 抽取第四个方法
     * 用来新增文章封面的图片到中间表
     *
     * @param dto
     */
    private void insertCoverImagesToWmNewsMaterial(WmNews wmNews, WmNewsDto dto, List<String> contentImagesList) {
        //获取封面图片集合 如果是单图多图或无图，则执行中间表的新增
        List<String> images = dto.getImages();

        //如果选择的是自动
        if (dto.getType() == null) {
            //从内容中提取图片作为封面
            //图片个数<1 封面无图
            //图片>=1或者<3,封面单图
            //图片>=3 三图
            if(contentImagesList.size()>=1&&contentImagesList.size()<3){
                images = contentImagesList.stream().limit(1).collect(Collectors.toList());
                //更新wm_news中的文章布局
                wmNews.setType((short) 1);
            } else if(contentImagesList.size()>=3){
                images = contentImagesList.stream().limit(3).collect(Collectors.toList());
                //更新wm_news中的文章布局
                wmNews.setType((short)3);
            } else {
                //无图
                wmNews.setType((short) 0);
            }
            //更新wm_news中的数据
            wmNews.setImages(StringUtils.join(images,','));
            updateById(wmNews);
        }
        //中间表的type应该为1表示封面引用
        extractedImagesToWmNewsMaterial(wmNews, images, (short) 1);
    }

    /**
     * 抽取的第三个方法，
     * 用来新增文章内容的图片到中间表
     *
     * @param wmNews
     * @param contentImagesList
     */
    private void insertContentImagesToWmNewsMaterial(WmNews wmNews, List<String> contentImagesList) {
        extractedImagesToWmNewsMaterial(wmNews, contentImagesList, (short) 0);
    }

    /**
     * 抽取的第五个方法
     * 根据图片地址查询出图片id，并新增到中间表
     *
     * @param wmNews
     * @param imagesList
     */
    private void extractedImagesToWmNewsMaterial(WmNews wmNews, List<String> imagesList,Short type) {
        //无图则不执行下列代码
        if (imagesList != null && imagesList.size() > 0) {
            //2.3.1.1 根据图片地址去查询素材表对应的id
            List<WmMaterial> wmMaterialList = wmMaterialService.list(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, imagesList));
            List<Integer> materialIdList = wmMaterialList.stream().map(wmMaterial -> wmMaterial.getId()).collect(Collectors.toList());
            //新增图片到中间表
            wmNewsMaterialMapper.saveRelations(materialIdList, wmNews.getId(), type);
        }
    }

    /**
     * 抽取的第二个方法
     * 从内容中抽取图片集合
     *
     * @return
     */
    private List<String> extractImagesFromContent(WmNewsDto dto) {
        //0 新建集合用于封装图片
        List<String> contentImagesList = new ArrayList<>();
        //1 获取文章内容
        String content = dto.getContent();
        //2 从内容中抽取图片，content是一个字符串形式的数组，里面存储的是map，转换格式
        List<Map> maps = JSONArray.parseArray(content, Map.class);
        //2.1 遍历
        for (Map map : maps) {
            if (map.get("type").equals("image")) {
                String ImageAddr = (String) map.get("value");
                contentImagesList.add(ImageAddr);
            }
        }
        return contentImagesList;
    }

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    /**
     * 抽取的第一个方法
     * 新增(提交审核或保存为草稿)文章或修改文章
     *
     * @param wmNews
     */
    private void insertOrUpdateNews(WmNews wmNews) {
        if (wmNews.getId() == null) {
            //新增文章
            save(wmNews);
        } else {
            //修改文章
            //1 先删除中间表数据
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, wmNews.getId()));
            //2 修改文章
            updateById(wmNews);
        }
    }


    /**
     * 点击修改的时候，就是根据文章id查询，跳转至编辑页面进行展示
     * @param id
     * @return
     */
    @Override
    public ResponseResult selectByNewsId(Integer id) {
        WmNews wmNews = getOne(Wrappers.<WmNews>lambdaQuery().eq(WmNews::getId, id));
        return ResponseResult.okResult(wmNews);
    }

    @Autowired
    private WmNewsMapper wmNewsMapper;
    /**
     * 文章删除
     * @param id
     * @return
     */
    @Override
    public ResponseResult deleteByNewsId(Integer id) {
        //根据id查出wm_news表数据判断状态
        WmNews wmNews = wmNewsMapper.selectById(id);
        if(wmNews.getStatus()==9&& wmNews.getEnable()==1){
            return ResponseResult.errorResult(AppHttpCodeEnum.ARTICLE_ENABLE);
        }
        //根据文章id删除中间表
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,id));
        //根据文章id删除wm_news表数据
        wmNewsMapper.deleteById(id);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     *发布文章的上下架
     * @param wmNewsDto
     * @return
     */
    @Override
    public ResponseResult downOrUp(WmNewsDto wmNewsDto) {
        //根据id去查询
        WmNews wmNews = wmNewsMapper.selectById(wmNewsDto.getId());
        if(wmNews.getStatus()!=9){
            return ResponseResult.errorResult(AppHttpCodeEnum.ARTICLE_NOPUBLISH);
        }
        wmNews.setEnable(wmNewsDto.getEnable());
        wmNewsMapper.updateById(wmNews);
        return null;
    }

}